package annTrain;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;

import aNN.BackpropagationThread;
import aNN.InputTargetPair;
import aNN.NeuralNetwork;
import aNN.NeuronOutputPair;



public class Trainer {
	
	
	public void PerformTraining()
	{
		Trainer trainer = new Trainer();
		trainer.Train("CNN_Handwritten_Digits.txt", "CNN_Handwritten_Digits_Trained.txt", "", "Training\\TrainingSet", 29, 29);
	}
	
	
	public void Train(String nnFile, String outputNNFile, String classificationFile, String tokenFolder, int inputWidth, int inputHeight)
	{
		NeuralNetwork cnn = new NeuralNetwork();
		TrainerHelper helper = new TrainerHelper();
		System.out.println(cnn.Import(System.getProperty("user.dir") + "\\" + nnFile));
		
		GenericImageTrainingSet trainingSet = new GenericImageTrainingSet(cnn.OutputLayer.Neurons.size(), inputWidth, inputHeight, true);
		trainingSet.LoadTrainingSet(System.getProperty("user.dir") + "\\" + tokenFolder, "", "");
		
		double eta = 0.001;
		double dMicron = 0.1;
		double etaFactor = 0.794183335;
		ResultError resultError = new ResultError(2);
		BackpropagationThread backpropagationThread = new BackpropagationThread(cnn);
		backpropagationThread.completed = true;
		
		
		for (int i = 0; i < 1000; i++)
		{
			double tempEta = Math.max(eta * Math.pow(etaFactor, i), 0.00005);
			trainingSet.GenerateRandomSequence(60000 / 10);
			TrainEpoch(cnn, i, helper, trainingSet, tempEta, 
					dMicron, backpropagationThread, resultError);
			cnn.Export(System.getProperty("user.dir") + "\\" + outputNNFile);
			AppendFileLine(System.getProperty("user.dir") + "\\" + "ErrorRate.txt", "Epoch " + i + "\t" + "eta " + tempEta + "\t" + resultError.GetMSE());
			
			String uploadFolder = "C:\\Users\\CC\\Dropbox\\ECE457b\\Project\\ECE457bProject";
			cnn.Export(uploadFolder + "\\" + outputNNFile);
			AppendFileLine(uploadFolder + "\\" + "ErrorRate.txt", "Epoch " + i + "\t" + "eta " + tempEta + "\t" + resultError.GetMSE());
		}
	}
	
	private void AppendFileLine(String fileName, String line)
	{
		Writer output;
		try {
			output = new BufferedWriter(new FileWriter(fileName, true));
			output.append(line + System.getProperty("line.separator"));
			output.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	private void TrainEpoch(NeuralNetwork cnn, int epochIndex,
			TrainerHelper helper, TrainingSet trainingSet, double eta,
			double dMicron, BackpropagationThread backpropagationThread, ResultError resultError) {
		int iteration = 0;
		resultError.NumErrors = 0;
		resultError.Reset();
		
		while (trainingSet.HasNext())
		{
			InputTargetPair inputsAndTargets = trainingSet.Next();
			if (inputsAndTargets == null)
				continue;
			NeuronOutputPair[] temp = cnn.TempCalculate(helper.CreateInputMap(cnn, inputsAndTargets));
			System.out.println("Epoch: " + epochIndex + "   Iteration: " + iteration);
			System.out.print("Error Square: " + resultError.AddResult(inputsAndTargets.Target, helper.GetNeuronOutputPairLastElements(temp, inputsAndTargets.Target.length)) + "    ");
			int target = helper.GetTarget(inputsAndTargets);
			double[] results = helper.GetNeuronOutputPairLastElements(temp, inputsAndTargets.Target.length);
			int result = helper.GetCalculatedResult(results);
			if (result != target)
			{
				resultError.NumErrors++;
			}
			System.out.print("Num errors: " + resultError.NumErrors + "     ");
			System.out.print(helper.GetTarget(inputsAndTargets) + ": ");
			for (int j = 0; j < inputsAndTargets.Target.length; j++)
			{
				System.out.print(results[j] + " ");
			}
			System.out.println();
//			while (backpropagationThread.completed == false);
//			backpropagationThread.adjustWeights();
			cnn.LoadTempCalculate(temp);
//			backpropagationThread = new BackpropagationThread(cnn, eta, dMicron, inputsAndTargets.Target);
//			backpropagationThread.start();

			cnn.BackPropagate(eta, dMicron, inputsAndTargets.Target, true);
			iteration++;
		}
	}
	
	
}


